package com.blb.edusearchservice.dao;

import com.alibaba.fastjson.JSON;
import com.blb.edusearchservice.pojo.ElasticsearchEntity;
import com.blb.edusearchservice.pojo.PageEntity;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.xml.crypto.Data;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Repository
public class ElasticsearchDao {

    @Autowired
    private RestHighLevelClient client;

    /**
     * 判断索引是否存在
     * @param index
     * @return
     * @throws IOException
     */
    public boolean existIndex(String index) throws IOException {
        GetIndexRequest request = new GetIndexRequest(index);
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        return exists;
    }

    /**
     * 创建索引
     * @param index
     * @throws IOException
     */
    public void createIndex(String index) throws IOException{
        CreateIndexRequest request = new CreateIndexRequest(index);
        client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println("创建"+index+"成功");
    }

    /**
     * 通用分页搜索方法
     * @param indexName
     * @param from
     * @param size
     * @param map
     * @param sort
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> PageEntity<T> searchPageByMap(String indexName,int from,int size,
                                             Map<String,String> map,Map<String,String> sort,
                                             Class<T> clazz,
                                             String... highlightFields) throws IOException {
        //创建搜索请求
        SearchRequest request = new SearchRequest(indexName);
        //请求生成器
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //创建bool组合查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //如果搜索条件不为空，就设置搜索条件
        if(map != null && map.size() > 0){
            for(String key : map.keySet()){
                String value = map.get(key);
                if(!StringUtils.isEmpty(value)){
                    //设置过滤条件
                    boolQuery.filter(QueryBuilders.matchPhraseQuery(key,value));
                }
            }
        }
        if(boolQuery.filter().size() > 0){
            //如果设置了过滤条件，就按过滤搜索
            builder.query(boolQuery);
        }
        //设置分页参数
        builder.from(from);
        builder.size(size);
        //设置排序 field type
        if(sort != null && sort.size() > 0){
            builder.sort(sort.get("field"),SortOrder.fromString(sort.get("type")));
        }
        //创建高亮生成器
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置高亮字段
        for(String field : highlightFields){
            highlightBuilder.field(field);
        }
        //设置前后标签
        highlightBuilder.preTags("<span style='color:red'>").postTags("</span>");
        builder.highlighter(highlightBuilder);
        //执行搜索获得结果
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] hits = response.getHits().getHits();
        List<T> data = new ArrayList<>();
        //将JSON格式的数据转换为Java对象
        for(SearchHit hit : hits){
            T res = JSON.parseObject(hit.getSourceAsString(),clazz);
            data.add(res);
            //获得所有高亮的字段
            Map<String, HighlightField> hFields = hit.getHighlightFields();
            for(String hField : hFields.keySet()){
                //获得反射字段
                try {
                    Field declaredField = clazz.getDeclaredField(hField);
                    //将字段的值替换为带高亮效果的属性值
                    declaredField.setAccessible(true);
                    Text[] fragments = hFields.get(hField).fragments();
                    if(declaredField != null && fragments.length > 0){
                        declaredField.set(res,fragments[0].string());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        //返回分页数据
        return new PageEntity<>(from/size+1,response.getHits().getTotalHits().value,size,data);
    }
    /**
     * 删除索引
     * @param index
     * @throws IOException
     */
    public void deleteIndex(String index) throws IOException{
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println("删除"+index+"成功");
    }

    /**
     * 批量添加
     * @param indexName
     * @param list
     * @throws IOException
     */
    public void bathData(String indexName, List<ElasticsearchEntity> list) throws IOException {
        BulkRequest request=new BulkRequest(indexName);
        list.forEach(entity ->{
            request.add(new IndexRequest().id(entity.getId())
            .source(JSON.toJSONString(entity.getData()),XContentType.JSON));
        });
        client.bulk(request,RequestOptions.DEFAULT);
        System.out.println("批量添加成功");
    }

    /**
     * 添加单个数据
     * @param indexName
     * @param entity
     * @throws IOException
     */
    public void addData(String indexName, ElasticsearchEntity entity) throws IOException {
        BulkRequest request=new BulkRequest(indexName);
       request.add(new IndexRequest().id(entity.getId())
               .source(JSON.toJSONString(entity.getData()),XContentType.JSON));
        client.bulk(request,RequestOptions.DEFAULT);
        System.out.println("添加成功");
    }
    public void deleteData(String indexName, String id) throws IOException {
        DeleteByQueryRequest request=new DeleteByQueryRequest(indexName);
        request.setQuery(QueryBuilders.termQuery("id",id));
        client.deleteByQuery(request,RequestOptions.DEFAULT);
        System.out.println("删除成功");
    }
}
